home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turnbull China Bikeride
/
Turnbull China Bikeride - Disc 2.iso
/
STUTTGART
/
LANG
/
C
/
LIB
/
OSLIB
/
README
< prev
next >
Wrap
Text File
|
1996-02-26
|
19KB
|
471 lines
12/09/95
Introduction
============
OSLib is a set of functions and C headers to provide complete
coverage of the RISC O S application programmer's interface in C. It
provides access from C code to all RISC O S system calls ("SWI's") which
is
efficient: often, memory access is completely avoided;
type-safe: every argument can be type-checked by the compiler;
obvious: a SWI is called by the "obvious" syntax;
complete: every SWI is covered;
register-safe: hides (often idiosyncratic) register allocation;
language-independent: although the headers are specific to C, the
library is not - any A P C S-conformant language can call it.
It also provides names for all the data structures and reason codes used
by the A P I. Code that uses it is superior to similar code using
_kernel_swi() or _swix(), both in terms of the compile-time checking
that is available, and the size and speed of the code generated.
In addition to the module files, there is also a file "types.h" which
contains macros and types useful for any programme.
This file explains how OSLib relates to the P R M descriptions of the
SWI's in complete detail. It is best read in conjunction with the header
files themselves.
The OSLib Structuring Conventions
=== ===== =========== ===========
Each header file provides
function prototypes
typedefs
macros
that completely specify the interface to a module. All symbols provided by
"<module>.h" are of the form <module>_<name> (except some of the form
<module><name>_<reason>). For functions, <name> is the name of the SWI,
converted to lower-case, and with underscores inserted between each word:
SWI Function
--- --------
OS_ReadLine os_read_line
Wimp_CreateWindow wimp_create_window
For typedefs, <name> is a sequence of words in lower-case, separated by
underscores:
Type Meaning
---- -------
os_colour a palette entry value (0xbbggrr00)
wimp_window a window definition structure
For macros, <name> is a sequence of words in upper-case, separated by
underscores:
Macro Meaning
----- -------
os_MODEVAR_XEIG_FACTOR a value for os_read_mode_variable
error_ESCAPE the error number of Escape (17)
wimp_ICON_NAME_LIMIT the largest length of an icon name
(all macros for maximum values end in _LIMIT). There is also a special set
of macros provided for more convenient handling of structures with a
variable number of trailing parts, as used for mode selectors or Wimp
window definitions, for example:
Macro Meaning
----- -------
os_PALETTE (nc) Declarator for a palette with |nc| colours
os_SIZEOF_PALETTE (nc) Size of that palette
wimp_WINDOW (ni) Declarator for a window with |ni| icons
wimp_SIZEOF_WINDOW (ni) Size of the complete window definition
Furthermore, every SWI number and SWI reason code has a macro defined of the
form <Module>_<Name> (in mixed case form):
Macro Value
----- -----
OS_WriteC 0
Font_FindFont 0x40081
These are rarely needed.
In fact, for each SWI, two functions are provided: one has a name
prefixed with an x and returns a value of type |os_error *|, which is non-
null if the SWI fails; the other does not start with an x, and never returns
an error: if the SWI fails, a signal (|SIGOSERROR|, number 10) is raised,
and may be caught by installing a signal handler for it. The non-x form can
therefore return a result, instead of having to write to an output argument:
for example, the SWI Wimp_CreateWindow can be called by either of the
prototypes
os_error *xwimp_create_window (wimp_window *window, wimp_w *w);
wimp_w wimp_create_window (wimp_window *window);
They have exactly the same effect if all goes well, but if there is an
error, the first just returns it, while the other raises |SIGOSERROR| and
does not return at all. (If you use the second, the signal handler for
|SIGOSERROR| can use _kernel_last_oserror() to find out what the error was.)
The function prototype is derived from the SWI description in the
following way. Arguments corresponding to input registers appear first in
order in the argument list, followed by the addresses of variables in which
the output registers' values are to be written. If an output register value
is not needed, a null pointer can be written in that position. (Since |int|
and all pointer types are 32 bits on the ARM, it doesn't matter which type
of null pointer is used.)
Most of the types are fully defined: e g, a |wimp_window| is a structure
type with all the fields defined with the right type and name to be passed to
any SWI that uses it. Some types are "abstract," however: they are exported
by a module, but the internal structure is not accessible to its clients.
The best way of representing this in C is by an unspecified pointer type: a
definition of the form
typedef struct <tag> *<type>
where the structure is never defined in full. Doing this allows the
compiler to typecheck arguments of these types, as in the wimp_-
create_window() example above.
In addition, various modules use values from name spaces that are
centrally allocated by Acorn. These include: |error_|, |message_|,
|...v|, |event_| and |upcall_|, and they each have their own prefix.
They correspond to error numbers, WIMP message numbers, vectors (which
are reason codes for OS_CallAVector), service calls (reason codes for
OS_ServiceCall), events (reason codes for OS_GenerateEvent) and upcalls
(reason codes for OS_UpCall), respectively. In cases where name clashes
are possible, the module name occurs in the <name> part:
error_BUFFER_MANAGER_BUFFER_TOO_SMALL
error_COLOUR_TRANS_BAD_DEPTH
(Vectors are represented by a suffix, |...v|, rather than a prefix, since
this is familiar.) These rules mean that if you are writing code for RISC
O S, and you avoid
(a) all names that start with the name <module> of any
"<module>.h" you need to include;
(b) all names that start with |error|, |message|, |event|
or |upcall|, or end with |v|;
then no names clashes will occur.
Types.h
=======
All OSLib header files ensure that "types.h" is included. This file
contains various types, macros for values, and function-like macros that
are generally useful. There are further macros in "macros.h." They are
described here:
Types
-----
|bits|: Used for flags values and masks, normally consisting of fields of
1 or more bits. Macros are normally provided to help with getting these
fields out: for a 1-bit field, a macro |X| such that
To Use
-- ---
Read the field (v & X) != NONE
Write a 0 v &= ~X
Write a 1 v |= X
and for a multi-bit field, macros X and X_SHIFT such that
To Use
-- ---
Read the field (v & X) >> X_SHIFT
Write a value |w| v = (v & ~X) | w << X_SHIFT.
|bool|: Used for a truth value.
|byte|: Used for a single byte value, as an alternative to |char| when the
values are just data, rather than being characters as such. It is an unsigned
type, which means that 2 instructions can be saved in P C C mode, where
|char| is signed and must be sign-extended.
Constant-like macros
------------- ------
|NULL|: the usual C null pointer constant.
|FALSE|: value of type |bool| representing falsehood.
|TRUE|: value of type |bool| representing truth.
|NONE|: value of type |bits| with all bits clear.
|ALL|: value of type |bits| with all bits set.
|SKIP|: may be used as a "don't care" value for |int|, pointers,
|bits|.
|SIG_LIMIT|: largest signal number + 1.
|_C|, |_Z|, |_N|, |_V|: masks for the flags in the P S R.
|DEC_WIDTH|: the length of INT_MAX (2147483647) printed with %d.
|SHORT_DEC_WIDTH|: the length of SHRT_MAX (32767) printed with %hd.
|LONG_DEC_WIDTH|: the length of LONG_MAX (2147483647) printed with %ld.
|OCT_WIDTH|: the length of UINT_MAX (37777777777) printed with %o.
|SHORT_OCT_WIDTH|: the length of USHRT_MAX (177777) printed with %ho.
|LONG_OCT_WIDTH|: the length of ULONG_MAX (37777777777) printed with %lo.
|UNSIGNED_WIDTH|: the length of UINT_MAX (4294967295) printed with %u.
|SHORT_UNSIGNED_WIDTH|: the length of USHRT_MAX (65535) printed with %hu.
|LONG_UNSIGNED_WIDTH|: the length of ULONG_MAX (4294967295) printed with
%lu.
|HEX_WIDTH|: the length of UINT_MAX (FFFFFFFF) printed with %x.
|SHORT_HEX_WIDTH|: the length of USHRT_MAX (FFFF) printed with %hx.
|LONG_HEX_WIDTH|: the length of ULONG_MAX (FFFFFFFF) printed with %lx.
|FLT_WIDTH|: the precision needed to distinguish 1 + FLT_EPSILON from 1
printed with %f.
|DBL_WIDTH|: the precision needed to distinguish 1 + DBL_EPSILON from 1
printed with %f.
|LDBL_WIDTH|: the precision needed to distinguish 1 + LDBL_EPSILON from 1
printed with %Lf.
|FLT_EXP_WIDTH|: the length of the exponent of FLT_MAX printed with %f.
|DBL_EXP_WIDTH|: the length of the exponent of DBL_MAX printed with %f.
|LDBL_EXP_WIDTH|: the length of the exponent of LDBL_MAX printed with %Lf.
|ERROR|: intended as an "out-of-band" value to be returned by functions
like fgetc() which return |EOF| on end-of-file. |ERROR| may be used to
indicate an error condition.
|UNKNOWN|: used to declare (but not define) arrays of unknown size, as
an argument to the type macros (e g, wimp_WINDOW()) described above.
Function-like macros
------------- ------
|WHETHER|: convert a bool value to a string.
|MAX|: larger of two values.
|MIN|: smaller of two values.
|MAXAB|: larger of two values and assign.
|MINAB|: smaller of two values and assign.
|ABS|: absolute value.
|SGN|: signum.
|DIM|: positive difference.
|SQR|: square.
|RATIO|: integer division, rounding to nearer.
|BOOL|: convert an integer to bool.
|UCHAR|: character corresponding to a digit (upper case preferred).
|LCHAR|: ditto, lower case.
|BINEXP|: 2 to the power of.
|ISDIGIT|: a digit?
|ISXDIGIT|: a hex digit?
|DIGIT|: if a digit, then which, else undefined.
|XDIGIT|: if a hex digit, then which, else undefined.
|DBLEQ|: equality for floating-point numbers (requires a tolerance)
|BIT|: the bit at an offset from a pointer.
|SET|: set a bit at an offset from a pointer.
|CLR|: clear a bit at an offset from a pointer.
|CLEAR|: clear a string.
|EMPTY|: is a string empty?
|NCOPY|: copy at most a given number of characters from a string, and
terminate it.
|STR_|: helper macro for STR.
|STR|: convert a macro to source string.
|COUNT|: number of elements in an array.
|ALIGN|: round an integer up to the next multiple of 4.
|WORD|: assembles an |int| from an unaligned byte pointer.
|SHORT|: assembles a |short| from an unaligned byte pointer.
Macros that "change the language"
------ ---- ------- --- ---------
(Not everyone likes using these!)
|AS| is the same as |.|, but can be used to let the reader know that the
left operand is a |union| rather than a |struct|.
|ASREF| is the same as |->|, but can be used to let the reader know that
the left operand is a |union *| rather than a |struct *|.
|_| is the same as |,|, but if used to separate the arguments of a macro
call is not recognised as a comma by the preprocessor. This lets you write
macros with variable numbers of arguments.
|__swi| is understood as a compiler directive by C release 5 (but not
by earlier versions of C, nor by CFront) to call a function using a SWI
instruction rather than by a BL. "Types.h" therefore includes some
directives to enable the uses of |__swi| in the headers to be "hidden"
in these cases by using -D__swi on the cc command line.
Macros to suppress compiler warnings
------ -- -------- -------- --------
|NOT_USED|: Suppress "variable not used" message.
|UNSET|: Suppress "variable may be used before being set" message.
Additional Structuring Rules
========== =========== =====
The design aims listed in paragraph 1 are not completely compatible. In
order to provide type-safety, it is necessary to provide multiple veneers
for some SWI's. These fall into two classes: where a SWI has multiple reason
codes, each reason code is provided with a separate function; and where a
SWI has two or more different variants, each variant is provided with its
own function.
Reason codes
------ -----
Many SWI's have several reason codes each of which has its own distinct
purpose and register usage. In this case, each reason code is provided with
its own function. (SWI's with a "reason code" parameter which does not
affect the interpretation of the other parameters are not treated like this:
instead, the reason codes are just provided as macros.) In some cases, one
reason code may itself have different sub-reason codes. In every case,
the functions that are derived from the SWI use the entirety of the SWI
name (with no underscore) as their prefix. Some have their own header
file (e g, OS_SpriteOp, reason codes in "osspriteop.h"), others share
the header file with the SWI (e g, PDriver_MiscOp, reason codes in
"pdriver.h"). Toolbox_object_misc_op() has a dynamically extensible set
of reason codes provided by object modules: these use the name of the
object, and are in the object's header file.
Where a header file name is longer than 10 characters, the full name
should be used in |#include| statements. FileCore-based filing systems will
truncate the file name to 10 characters, if the *Configure option 'Truncate'
is 'On' (which is recommended). This means that, for example, the line
|#include "messagetrans.h"| will work on all filing systems: FileCore-based
ones will convert the name to "messagetra.h."
OS_WriteI might be considered to have a reason code (the character to be
written), but since it is part of the SWI number, each character has a
separate function. This is not worthwhile for printing characters, but for
other VDU codes gives useful calls like os_clg() (to clear the graphics
window), os_bell() (to ring the bell) etc. (The complete list is
in "os.h.")
Many of the reason codes of OS_CallAVector have been omitted, namely,
those where there are many sub-reason codes, and the purpose of the vector
is exactly duplicated by a SWI or SWI's. So you will not find findv_-
openin() (to call sub-reason code OSFind_OpenIn of reason code FindV of
SWI OS_CallAVector), because it is identical in purpose to osfind_openin().
If there are reason codes but no SWI, the reason codes do have functions
provided (e g, PaletteV), and if there are no reason codes, the function is
provided even if it does duplicate a SWI - for example, you can call
os_writec() or wrchv() with the same effect (unless you are implementing
them, of course). This is all just to keep the library size down: if it
causes a problem, it can be reviewed. (Since calls to OS_GenerateEvent
and OS_UpCall are already distributed through many files, vectored
versions of them would have to be distributed in the same way.)
Lastly, calls provided by FileSwitch are in "fileswitch.h", unless they
have their own header. (The separate headers are "osargs.h," osfile.h,"
osfind.h," osfscontrol.h," "osgbpb.h.") Also, some of the types that
might be expected to be defined in these headers are actually defined in
"fileswitch.h," to avoid circular references.
Variants
--------
Some SWI's have two or more different functions that call them, because
they have two different calling conventions that cannot be easily captured
using C's type system. These should be obvious from the name; failing
that, the header file says exactly which SWI is called, and which values
are placed into which registers. A few examples are described here, to
give an idea of why variants exist.
Colourtrans_select_table_for_sprite() (variant of
colourtrans_select_- table()) takes an |osspriteop_area *| and an
|osspriteop_id|, rather than an |os_mode| and an |os_palette *|, as its
first two arguments. The same applies to
colourtrans_generate_table_for_sprite() (variant of colourtrans_-
generate_table()) and colourtrans_select_gcol_table_for_sprite() (variant of
colourtrans_select_gcol_table()).
Os_read_colour() (variant of os_set_colour()) is provided so that
os_set_colour() can remain backwards-compatible.
Squash_compress_return_sizes() (variant of squash_compress()) and
squash_decompress_return_sizes() (variant of squash_decompress()) are
provided because of the different purposes dependent on bit 3 of R0.
Stringset{set,get}selected_string() and
stringset{set,get}selected_index() are both provided, to allow correct
typechecking of the string or integer argument.
Territory_read_symbols() is divided into 3 variants, territory_read_-
boolean_symbols(), territory_read_integer_symbols() and territory_read_-
string_symbols(), because different symbols have different types.
Wimp_send_message_to_window() (variant of wimp_send_message()) takes
a |wimp_w| and a |wimp_i| rather than a |wimp_t|, and returns a result
(the task handle) which wimp_send_message() does not.
Conclusion
==========
Although there seem to be a lot of rules, that is because the RISC O S
A P I is large. For normal application programming, most of it is not
needed: applications don't normally deal with vectors, upcalls or service
calls, for example, or do any direct access to disc structures. However,
this is not ruled out. The C headers contain the complete description of
exactly what each function does in terms of the mapping of the arguments to
ARM registers, so no other documentation is needed.
OSLib provides a very convenient interface to the RISC O S programmer,
since all the facilities of the C compiler are available to catch errors
and generate good code. It is conceptually very small, in that it is
completely documented by this file. As a bonus, code written using it is
smaller and faster than code written using other means.
Disclaimer
==========
OSLib is copyright © 1995 Acorn Computers Ltd. It is distributed in
the hope that it will be useful, but without any warranty; without even
the implied warranty of merchantability or fitness for a particular
purpose.
Fault reports and suggestions for improvement may be sent to the
author, Jonathan Coxhead <jcoxhead@acorn.co.uk>. Although this is an
Acorn address, OSLib is not an official Acorn product.